package cn.workreport.modules.upload.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.Img;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.util.ObjectUtil;
import cn.workreport.modules.common.exception.ServiceException;
import cn.workreport.modules.common.vo.PageVO;
import cn.workreport.modules.upload.entity.Upload;
import cn.workreport.modules.upload.enums.BusinessKeyEnum;
import cn.workreport.modules.upload.mapper.UploadMapper;
import cn.workreport.modules.upload.service.IUploadService;
import cn.workreport.util.JsonResult;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * 文件上传 业务接口实现类
 * </p>
 *
 * @author yyf
 * @since 2022-01-19
 */
@Slf4j
@Service
public class UploadServiceImpl extends ServiceImpl<UploadMapper, Upload> implements IUploadService {

    private static final String separator = "/";

    // 上传文件保存的绝对路径
    @Value("${upload.location}")
    private String uploadLocation;

    @Override
    public void wrapEntity(Upload entity) {

    }

    @Override
    public PageVO<Upload> pageEntity(IPage<Upload> page, Wrapper<Upload> queryWrapper) {
        IPage<Upload> pageResult = this.page(page, queryWrapper);
        return new PageVO<>(pageResult);
    }

    @Override
    public Upload getByIdEntity(Integer id) {
        return null;
    }

    @Override
    public JsonResult<?> saveOrUpdateEntity(Upload entity) {
        Upload newEntity = new Upload();

        BeanUtil.copyProperties(
                entity,
                newEntity,
                CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true)
        );

        boolean isSuccess = super.saveOrUpdate(newEntity);
        if (!isSuccess) {
            return JsonResult.fail("操作失败");
        }
        return JsonResult.ok();
    }

    @Override
    public JsonResult<?> removeByIdEntity(Integer id) {
        boolean isSuccess = super.removeById(id);
        if (!isSuccess) {
            return JsonResult.fail();
        }
        return JsonResult.ok();
    }

    @Override
    public JsonResult<?> removeByIdsEntity(List<Integer> ids) {
        for (Integer id : ids) {
            JsonResult<?> jsonResult = removeByIdEntity(id);
            if (!jsonResult.getState().equals(JsonResult.SUCCESS)) {
                return JsonResult.fail();
            }
        }
        return JsonResult.ok();
    }

    @Override
    public Upload base64TransferImgEntity(
            String base64Str,
            String realPath,
            String fileDir,
            String suffix,
            BusinessKeyEnum businessKey
    ) {
        if (
                StringUtils.isBlank(base64Str)
                        || StringUtils.isBlank(realPath)
                        || StringUtils.isBlank(fileDir)
                        || StringUtils.isBlank(suffix)
                        || ObjectUtils.isEmpty(businessKey)
        ) {
            return null;
        }
        // 保存的文件名
        String fileName = UUID.randomUUID().toString() + suffix;
        // 保存文件的相对路径
        String filePath = fileDir + separator + fileName;
        log.info("保存文件的相对路径 ===>" + filePath);
        // 保存文件的绝对路径
        String fileLocation = realPath + separator + fileDir + separator + fileName;
        log.info("保存文件的绝对路径 ===>" + fileLocation);
        fileLocation = URLDecoder.decode(fileLocation, StandardCharsets.UTF_8);
        // 判断文件夹是否存在，不存在则创建
//        File dir = new File(realPath + separator + fileDir);
//        if (!dir.exists()) {
//            dir.mkdirs();
//        }
        String dir = realPath + separator + fileDir;
        if (!FileUtil.exist(dir)) {
            FileUtil.mkdir(dir);
        }
        // 转文件流并压缩保存文件
        try {
            BufferedImage bufferedImage = ImgUtil.toImage(base64Str.substring(base64Str.indexOf(",") + 1));
            Img.from(bufferedImage).setQuality(0.2) // 压缩比率
                    .write(FileUtil.file(fileLocation));
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("文件解析失败");
        }
        // 读取文件大小
        FileReader fileReader = new FileReader(fileLocation);
        byte[] bytes = fileReader.readBytes();
        long fileSize = bytes.length;
        // 封装文件信息对象
        Upload uploadEntity = new Upload();
        uploadEntity.setBusinessKey(businessKey);
        uploadEntity.setFileName(fileName);
        uploadEntity.setFileLocation(fileLocation);
        uploadEntity.setFilePath(filePath);
        uploadEntity.setFileSize(fileSize);
        return uploadEntity;
    }

    @Override
    public Upload uploadImage(MultipartFile file, BusinessKeyEnum businessKey, String type) {
        // 判断文件是否为空
        if (file.isEmpty()) {
            return null;
        }
        if (ObjectUtil.isEmpty(businessKey)) {
            throw new ServiceException("参数 businessKey 不能为空");
        }
        // 获取原始文件名
        String fileOriginName = file.getOriginalFilename();
        // 获取文件名后缀
        String suffix = "";
        int suffixIndex = fileOriginName.lastIndexOf(".");
        if (suffixIndex > 0) {
            suffix = fileOriginName.substring(suffixIndex);
        }
        log.info("suffix ===>" + suffix);
        String[] allowSuffixList = {".jpeg", ".jpg", ".png"};
        boolean isAllow = false;
        for (String item : allowSuffixList) {
            if (item.equals(suffix)) {
                isAllow = true;
            }
        }
        if (!isAllow) {
            throw new ServiceException("文件格式只能为.jpeg、.jeg、.png");
        }
        // 强制改成.jpg格式，因为压缩输出图像只支持jpg文件
        suffix = ".jpg";
        String realPath = this.uploadLocation;
        // 保存文件的文件夹名称（按日期分类文件夹）
        String fileDir = "images" + separator + "todo" + separator + DateUtil.format(new Date(), "yyyy-MM-dd");
        // 保存的文件名
        String fileName = UUID.randomUUID().toString() + suffix;
        // 保存文件的相对路径
        String filePath = fileDir + separator + fileName;
        // 保存文件的绝对路径
        String fileLocation = realPath + separator + fileDir + separator + fileName;
        fileLocation = URLDecoder.decode(fileLocation, StandardCharsets.UTF_8);
        String dir = realPath + separator + fileDir;
        if (!FileUtil.exist(dir)) {
            FileUtil.mkdir(dir);
        }
        // 压缩文件
        try {
            Img.from(file.getInputStream()).setQuality(0.4) // 压缩比率
                    .write(FileUtil.file(fileLocation));
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("文件解析失败");
        }
        // 保存文件
//        File dest = new File(dir, fileName);
//        try {
//            file.transferTo(dest);
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new ServiceException("保存文件失败");
//        }
        // 读取文件大小
        FileReader fileReader = new FileReader(fileLocation);
        byte[] bytes = fileReader.readBytes();
        long fileSize = bytes.length;
        // 封装文件信息对象
        Upload uploadEntity = new Upload();
        uploadEntity.setBusinessKey(businessKey);
        uploadEntity.setFileName(fileName);
        uploadEntity.setFileLocation(fileLocation);
        uploadEntity.setFilePath(filePath);
        uploadEntity.setFileSize(fileSize);
        if (!this.saveOrUpdate(uploadEntity)) {
            throw new ServiceException("保存文件数据失败");
        }
        return uploadEntity;
    }
}

